package cz.muni.fi.pa165.dundd.web;

import cz.muni.fi.pa165.dundd.dto.HeroDTO;
import cz.muni.fi.pa165.dundd.dto.HeroRoleDTO;
import cz.muni.fi.pa165.dundd.dto.TroopDTO;
import cz.muni.fi.pa165.dundd.service.HeroRoleService;
import cz.muni.fi.pa165.dundd.service.HeroService;
import cz.muni.fi.pa165.dundd.service.TroopService;
import cz.muni.fi.pa165.dundd.serviceImpl.AdministratorLoginDetails;
import cz.muni.fi.pa165.dundd.serviceImpl.HeroLoginDetails;
import static cz.muni.fi.pa165.dundd.web.BaseActionBean.escapeHTML;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import net.sourceforge.stripes.action.*;
import net.sourceforge.stripes.controller.LifecycleStage;
import net.sourceforge.stripes.integration.spring.SpringBean;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;
import net.sourceforge.stripes.validation.ValidationErrorHandler;
import net.sourceforge.stripes.validation.ValidationErrors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;

/**
 *
 * @author xszanto1, xdemocko
 */
@UrlBinding("/heroes/{$event}/{hero.id}")
public class HeroActionBean extends BaseActionBean implements ValidationErrorHandler {

    final static Logger log = LoggerFactory.getLogger(HeroActionBean.class);
    @SpringBean
    TroopService troopService;
    private List<TroopDTO> troops = new ArrayList<>();

    public List<TroopDTO> getTroops() {
        return troopService.retrieveAllTroops();
    }
    @SpringBean
    HeroRoleService heroRoleService;
    private List<HeroRoleDTO> heroRoles = new ArrayList<>();

    public List<HeroRoleDTO> getHeroRoles() {
        return heroRoleService.retrieveAllRoles();
    }
    private List<HeroRoleDTO> heroRolesTemp = new ArrayList<>();

    public List<HeroRoleDTO> getHeroRolesTemp() {
        return heroService.retrieveRolesOfHero(hero);
    }
    @SpringBean
    HeroService heroService;
    private List<HeroDTO> heroes;
    @ValidateNestedProperties(value = {
        @Validate(on = {"add", "save"}, field = "name", required = true)
    })
    private HeroDTO hero;
    
    //<editor-fold defaultstate="collapsed" desc="get set">
    public HeroDTO getHero() {
        return hero;
    }

    public void setHero(HeroDTO hero) {
        this.hero = hero;
    }
    private TroopDTO troop;

    public TroopDTO getTroop() {
        return troop;
    }

    public void setTroop(TroopDTO troop) {
        this.troop = troop;
    }
    private HeroRoleDTO heroRole;

    public HeroRoleDTO getHeroRole() {
        return heroRole;
    }

    public void setHeroRole(HeroRoleDTO heroRole) {
        this.heroRole = heroRole;
    }
    private Long heroRoleId;

    public Long getHeroRoleId() {
        return heroRoleId;
    }

    public void setHeroRoleId(Long heroRoleId) {
        this.heroRoleId = heroRoleId;
    }
//</editor-fold>
    
    public Resolution add() {
        if (troop != null) {
            hero.setMyParty(troop);
        }
        heroService.createHero(hero);
        getContext().getMessages().add(new LocalizableMessage("hero.add.message", escapeHTML(hero.getName())));
        return new RedirectResolution(this.getClass(), "list");
    }

    @DefaultHandler
    public Resolution list() {
        heroes = heroService.retrieveAllHeroes();
        return new ForwardResolution("/hero/list.jsp");
    }

    public List<HeroDTO> getHeroes() {
        return heroes;
    }

    public Resolution delete() {
        Object o = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (o instanceof HeroLoginDetails) {
            HeroLoginDetails heroLogin = (HeroLoginDetails) o;
            if (!heroLogin.getUsername().equals(hero.getName())){
                return new ForwardResolution("/403.jsp");
            }
        } 
        //only id is filled by the form
        hero = heroService.retrieveHero(hero.getId());
        heroService.deleteHero(hero);
        getContext().getMessages().add(new LocalizableMessage("hero.delete.message",
                escapeHTML(hero.getName())));
        return new RedirectResolution(this.getClass(), "list");
    }

    public Resolution deleteRole() {
        Object o = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (o instanceof HeroLoginDetails) {
            HeroLoginDetails heroLogin = (HeroLoginDetails) o;
            if (!heroLogin.getUsername().equals(hero.getName())){
                return new ForwardResolution("/403.jsp");
            }
        } 
        //only id is filled by the form
        hero = heroService.retrieveHero(hero.getId());
        heroRole = heroRoleService.retrieveRoleById(heroRoleId);
        heroService.deleteRoleOfHero(hero, heroRole);
        return new RedirectResolution(this.getClass(), "list");
    }

    @Override
    public Resolution handleValidationErrors(ValidationErrors errors) throws Exception {
        //fill up the data for the table if validation errors occured
        //return null to let the event handling continue
        heroes = heroService.retrieveAllHeroes();
        return null;
    }

    @Before(stages = LifecycleStage.BindingAndValidation, on = {"edit", "save"})
    public void loadHeroFromDatabase() {
        String ids = getContext().getRequest().getParameter("hero.id");
        if (ids == null) {
            return;
        }
        hero = heroService.retrieveHero(Long.parseLong(ids));
    }

    @Before(stages = LifecycleStage.BindingAndValidation, on = {"add", "edit", "save"})
    public void loadTroopFromDatabase() {
        String ids = getContext().getRequest().getParameter("hero.myParty");
        if (ids == null) {
            return;
        }
        troop = troopService.retrieveTroopById(Long.parseLong(ids));
    }

    public Resolution edit() {
        Object o = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (o instanceof HeroLoginDetails) {
            HeroLoginDetails heroLogin = (HeroLoginDetails) o;
            if (!heroLogin.getUsername().equals(hero.getName())){
                return new ForwardResolution("/403.jsp");
            }
        } 
        return new ForwardResolution("/hero/edit.jsp");
    }

    @Before(stages = LifecycleStage.BindingAndValidation, on = {"editroles"})
    public void loadHeroRolesTempFromDatabase() {
        String ids = getContext().getRequest().getParameter("hero.id");
        if (ids == null) {
            return;
        }
        hero = heroService.retrieveHero(Long.parseLong(ids));
        heroRolesTemp = heroService.retrieveRolesOfHero(hero);
    }

    @Before(stages = LifecycleStage.BindingAndValidation, on = {"saverole"})
    public void loadHeroRoleFromDatabase() {
        String ids = getContext().getRequest().getParameter("heroRoleId");
        if (ids == null) {
            return;
        }
        heroRole = heroRoleService.retrieveRoleById(Long.parseLong(ids));
    }

    public Resolution editroles() {
        Object o = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (o instanceof HeroLoginDetails) {
            HeroLoginDetails heroLogin = (HeroLoginDetails) o;
            if (!heroLogin.getUsername().equals(hero.getName())){
                return new ForwardResolution("/403.jsp");
            }
        } 
        return new ForwardResolution("/hero/roles.jsp");
    }

    public Resolution save() {
        if (troop != null) {
            hero.setMyParty(troop);
        }
        heroService.updateHero(hero);
        return new RedirectResolution(this.getClass(), "list");
    }

    public Resolution saverole() {
        if (heroRole != null) {
            heroService.addRoleToHero(hero, heroRole);
        }
        return new RedirectResolution(this.getClass(), "list");
    }
}
